#include "CommandHandler.hpp"
#include <iostream>
#include <fstream>
#include <sstream>
#include <dirent.h>
#include <unistd.h>
#include <sys/stat.h>

// 构造函数：初始化命令映射
CommandHandler::CommandHandler() : logger_(spdlog::get("ftpserverlog"))
{
    // 将命令与对应的处理函数绑定
    cmd_map_["USER"] = &CommandHandler::HandleUSER;
    cmd_map_["PASS"] = &CommandHandler::HandlePASS;
    cmd_map_["CWD"] = &CommandHandler::HandleCWD;
    cmd_map_["CDUP"] = &CommandHandler::HandleCDUP;
    cmd_map_["MKD"] = &CommandHandler::HandleMKD;
    cmd_map_["RMD"] = &CommandHandler::HandleRMD;
    cmd_map_["LIST"] = &CommandHandler::HandleLIST;
    cmd_map_["NLST"] = &CommandHandler::HandleNLST;
    cmd_map_["RETR"] = &CommandHandler::HandleRETR;
    cmd_map_["STOR"] = &CommandHandler::HandleSTOR;
    cmd_map_["STOU"] = &CommandHandler::HandleSTOU;
    cmd_map_["DELE"] = &CommandHandler::HandleDELE;
    cmd_map_["PASV"] = &CommandHandler::HandlePASV;
    cmd_map_["PORT"] = &CommandHandler::HandlePORT;
    cmd_map_["TYPE"] = &CommandHandler::HandleTYPE;
    cmd_map_["HELP"] = &CommandHandler::HandleHELP;
    cmd_map_["NOOP"] = &CommandHandler::HandleNOOP;
    cmd_map_["QUIT"] = &CommandHandler::HandleQUIT;
    cmd_map_["ABOR"] = &CommandHandler::HandleABOR;

    // 初始化当前路径
    current_path_ = std::filesystem::current_path().string();
}

// 设置会话对象
void CommandHandler::SetSession(std::shared_ptr<class Session> session)
{
    session_ = session;
}

// 设置数据连接套接字
void CommandHandler::SetDataSocket(int data_socket)
{
    data_socket_ = data_socket;
}

// 设置数据端口
void CommandHandler::SetDataPort(int port)
{
    data_port_ = port;
}

// 设置数据IP
void CommandHandler::SetDataIP(const std::string &ip)
{
    data_ip_ = ip;
}

// 解析命令并分派到具体处理函数
void CommandHandler::Parse(const std::string &cmd)
{
    // 将命令转换为大写（保证统一处理）
    std::string upper_cmd = cmd;
    for (auto &c : upper_cmd)
    {
        c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
    }

    // 分割命令和参数
    std::istringstream iss(cmd);
    std::string command;
    iss >> command;

    // 记录原始命令
    logger_->info("cmd: {}", cmd);

    // 查找命令是否存在
    auto it = cmd_map_.find(upper_cmd);
    if (it != cmd_map_.end())
    {
        // 找到命令，调用对应的成员函数
        (this->*(it->second))();
    }
    else
    {
        logger_->error(" 500 Unknown command : {}", cmd);
        std::cout << "500 Unknown command." << std::endl;
    }
}

// 处理USER命令
void CommandHandler::HandleUSER()
{
    std::istringstream iss(session_->GetLastCommand());
    std::string cmd, username;
    iss >> cmd >> username;

    if (username.empty())
    {
        std::cout << "501 Syntax error in parameters or arguments." << std::endl;
        return;
    }

    username_ = username;
    authenticated_ = false;
    std::cout << "331 User name okay, need password." << std::endl;
}

// 处理PASS命令
void CommandHandler::HandlePASS()
{
    std::istringstream iss(session_->GetLastCommand());
    std::string cmd, password;
    iss >> cmd >> password;

    if (username_.empty())
    {
        std::cout << "503 Bad sequence of commands." << std::endl;
        return;
    }

    // 简单的密码验证（实际应用中应使用更安全的方式）
    if (password == "password")
    {
        authenticated_ = true;
        std::cout << "230 User logged in, proceed." << std::endl;
    }
    else
    {
        std::cout << "530 Not logged in." << std::endl;
    }
}

// 处理CWD命令（切换目录）
void CommandHandler::HandleCWD()
{
    if (!authenticated_)
    {
        std::cout << "530 Please login with USER and PASS." << std::endl;
        return;
    }

    std::istringstream iss(session_->GetLastCommand());
    std::string cmd, path;
    iss >> cmd >> path;

    if (path.empty())
    {
        std::cout << "501 Syntax error in parameters or arguments." << std::endl;
        return;
    }

    try
    {
        std::filesystem::path new_path = std::filesystem::absolute(path, current_path_);
        if (std::filesystem::exists(new_path) && std::filesystem::is_directory(new_path))
        {
            current_path_ = new_path.string();
            std::cout << "250 Directory changed successfully." << std::endl;
        }
        else
        {
            std::cout << "550 No such directory." << std::endl;
        }
    }
    catch (const std::exception &e)
    {
        std::cout << "550 Failed to change directory." << std::endl;
    }
}

// 处理CDUP命令（返回上级目录）
void CommandHandler::HandleCDUP()
{
    if (!authenticated_)
    {
        std::cout << "530 Please login with USER and PASS." << std::endl;
        return;
    }

    try
    {
        std::filesystem::path parent = std::filesystem::path(current_path_).parent_path();
        if (parent != current_path_)
        {
            current_path_ = parent.string();
            std::cout << "250 Directory changed successfully." << std::endl;
        }
        else
        {
            std::cout << "250 Current directory is root." << std::endl;
        }
    }
    catch (const std::exception &e)
    {
        std::cout << "550 Failed to change directory." << std::endl;
    }
}

// 处理MKD命令（创建目录）
void CommandHandler::HandleMKD()
{
    if (!authenticated_)
    {
        std::cout << "530 Please login with USER and PASS." << std::endl;
        return;
    }

    std::istringstream iss(session_->GetLastCommand());
    std::string cmd, path;
    iss >> cmd >> path;

    if (path.empty())
    {
        std::cout << "501 Syntax error in parameters or arguments." << std::endl;
        return;
    }

    try
    {
        std::filesystem::path new_path = std::filesystem::absolute(path, current_path_);
        if (std::filesystem::create_directory(new_path))
        {
            std::cout << "257 Directory created successfully." << std::endl;
        }
        else
        {
            std::cout << "550 Failed to create directory." << std::endl;
        }
    }
    catch (const std::exception &e)
    {
        std::cout << "550 Failed to create directory." << std::endl;
    }
}

// 处理RMD命令（删除目录）
void CommandHandler::HandleRMD()
{
    if (!authenticated_)
    {
        std::cout << "530 Please login with USER and PASS." << std::endl;
        return;
    }

    std::istringstream iss(session_->GetLastCommand());
    std::string cmd, path;
    iss >> cmd >> path;

    if (path.empty())
    {
        std::cout << "501 Syntax error in parameters or arguments." << std::endl;
        return;
    }

    try
    {
        std::filesystem::path dir_path = std::filesystem::absolute(path, current_path_);
        if (std::filesystem::exists(dir_path) && std::filesystem::is_directory(dir_path))
        {
            std::filesystem::remove_all(dir_path);
            std::cout << "250 Directory removed successfully." << std::endl;
        }
        else
        {
            std::cout << "550 No such directory." << std::endl;
        }
    }
    catch (const std::exception &e)
    {
        std::cout << "550 Failed to remove directory." << std::endl;
    }
}

// 处理LIST命令（列出目录内容）
void CommandHandler::HandleLIST()
{
    if (!authenticated_)
    {
        std::cout << "530 Please login with USER and PASS." << std::endl;
        return;
    }

    std::cout << "150 Here comes the directory listing." << std::endl;

    // 打开数据连接
    if (data_socket_ == -1)
    {
        std::cout << "425 Use PASV or PORT first." << std::endl;
        return;
    }

    try
    {
        DIR *dir;
        struct dirent *entry;
        std::string listing;

        dir = opendir(current_path_.c_str());
        if (dir == nullptr)
        {
            std::cout << "550 Failed to open directory." << std::endl;
            return;
        }

        while ((entry = readdir(dir)) != nullptr)
        {
            struct stat statbuf;
            std::string full_path = current_path_ + "/" + entry->d_name;

            if (stat(full_path.c_str(), &statbuf) == 0)
            {
                std::string line;
                line += (S_ISDIR(statbuf.st_mode)) ? "d" : "-";
                line += (statbuf.st_mode & S_IRUSR) ? "r" : "-";
                line += (statbuf.st_mode & S_IWUSR) ? "w" : "-";
                line += (statbuf.st_mode & S_IXUSR) ? "x" : "-";
                line += (statbuf.st_mode & S_IRGRP) ? "r" : "-";
                line += (statbuf.st_mode & S_IWGRP) ? "w" : "-";
                line += (statbuf.st_mode & S_IXGRP) ? "x" : "-";
                line += (statbuf.st_mode & S_IROTH) ? "r" : "-";
                line += (statbuf.st_mode & S_IWOTH) ? "w" : "-";
                line += (statbuf.st_mode & S_IXOTH) ? "x" : "-";

                std::ostringstream size_stream;
                size_stream << statbuf.st_size;
                line += " " + size_stream.str();

                std::string time_str = ctime(&statbuf.st_mtime);
                time_str = time_str.substr(0, time_str.length() - 1); // 去掉换行符
                line += " " + time_str + " " + entry->d_name + "\n";

                listing += line;
            }
        }
        closedir(dir);

        // 发送数据
        SendData(listing);
        std::cout << "226 Directory list sent successfully." << std::endl;
    }
    catch (const std::exception &e)
    {
        std::cout << "550 Failed to list directory." << std::endl;
    }
}

// 处理NLST命令（列出文件名）
void CommandHandler::HandleNLST()
{
    if (!authenticated_)
    {
        std::cout << "530 Please login with USER and PASS." << std::endl;
        return;
    }

    std::cout << "150 Here comes the file listing." << std::endl;

    // 打开数据连接
    if (data_socket_ == -1)
    {
        std::cout << "425 Use PASV or PORT first." << std::endl;
        return;
    }

    try
    {
        DIR *dir;
        struct dirent *entry;
        std::string listing;

        dir = opendir(current_path_.c_str());
        if (dir == nullptr)
        {
            std::cout << "550 Failed to open directory." << std::endl;
            return;
        }

        while ((entry = readdir(dir)) != nullptr)
        {
            listing += std::string(entry->d_name) + "\n";
        }
        closedir(dir);

        // 发送数据
        SendData(listing);
        std::cout << "226 File list sent successfully." << std::endl;
    }
    catch (const std::exception &e)
    {
        std::cout << "550 Failed to list files." << std::endl;
    }
}

// 处理RETR命令（下载文件）
void CommandHandler::HandleRETR()
{
    if (!authenticated_)
    {
        std::cout << "530 Please login with USER and PASS." << std::endl;
        return;
    }

    std::istringstream iss(session_->GetLastCommand());
    std::string cmd, filename;
    iss >> cmd >> filename;

    if (filename.empty())
    {
        std::cout << "501 Syntax error in parameters or arguments." << std::endl;
        return;
    }

    std::string full_path = current_path_ + "/" + filename;

    if (!std::filesystem::exists(full_path))
    {
        std::cout << "550 File not found." << std::endl;
        return;
    }

    std::cout << "150 Opening data connection for file download." << std::endl;

    // 打开数据连接
    if (data_socket_ == -1)
    {
        std::cout << "425 Use PASV or PORT first." << std::endl;
        return;
    }

    if (SendFile(full_path))
    {
        std::cout << "226 File transfer completed successfully." << std::endl;
    }
    else
    {
        std::cout << "550 File transfer failed." << std::endl;
    }
}

// 处理STOR命令（上传文件）
void CommandHandler::HandleSTOR()
{
    if (!authenticated_)
    {
        std::cout << "530 Please login with USER and PASS." << std::endl;
        return;
    }

    std::istringstream iss(session_->GetLastCommand());
    std::string cmd, filename;
    iss >> cmd >> filename;

    if (filename.empty())
    {
        std::cout << "501 Syntax error in parameters or arguments." << std::endl;
        return;
    }

    std::string full_path = current_path_ + "/" + filename;

    std::cout << "150 Opening data connection for file upload." << std::endl;

    // 打开数据连接
    if (data_socket_ == -1)
    {
        std::cout << "425 Use PASV or PORT first." << std::endl;
        return;
    }

    if (ReceiveFile(full_path))
    {
        std::cout << "226 File transfer completed successfully." << std::endl;
    }
    else
    {
        std::cout << "550 File transfer failed." << std::endl;
    }
}

// 处理STOU命令（唯一上传文件）
void CommandHandler::HandleSTOU()
{
    if (!authenticated_)
    {
        std::cout << "530 Please login with USER and PASS." << std::endl;
        return;
    }

    std::istringstream iss(session_->GetLastCommand());
    std::string cmd, filename;
    iss >> cmd >> filename;

    // 生成唯一文件名
    if (filename.empty())
    {
        filename = "ftpfile";
    }

    std::string base_path = current_path_ + "/" + filename;
    std::string unique_path = base_path;
    int counter = 1;

    while (std::filesystem::exists(unique_path))
    {
        unique_path = base_path + "." + std::to_string(counter++);
    }

    std::cout << "150 Opening data connection for unique file upload." << std::endl;

    // 打开数据连接
    if (data_socket_ == -1)
    {
        std::cout << "425 Use PASV or PORT first." << std::endl;
        return;
    }

    if (ReceiveFile(unique_path))
    {
        std::cout << "226 File transfer completed successfully." << std::endl;
        std::cout << "227 Unique file name: " << std::filesystem::path(unique_path).filename().string() << std::endl;
    }
    else
    {
        std::cout << "550 File transfer failed." << std::endl;
    }
}

// 处理DELE命令（删除文件）
void CommandHandler::HandleDELE()
{
    if (!authenticated_)
    {
        std::cout << "530 Please login with USER and PASS." << std::endl;
        return;
    }

    std::istringstream iss(session_->GetLastCommand());
    std::string cmd, filename;
    iss >> cmd >> filename;

    if (filename.empty())
    {
        std::cout << "501 Syntax error in parameters or arguments." << std::endl;
        return;
    }

    std::string full_path = current_path_ + "/" + filename;

    if (std::filesystem::exists(full_path) && !std::filesystem::is_directory(full_path))
    {
        if (std::filesystem::remove(full_path))
        {
            std::cout << "250 File deleted successfully." << std::endl;
        }
        else
        {
            std::cout << "550 Failed to delete file." << std::endl;
        }
    }
    else
    {
        std::cout << "550 File not found." << std::endl;
    }
}

// 处理PASV命令（被动模式）
void CommandHandler::HandlePASV()
{
    if (!authenticated_)
    {
        std::cout << "530 Please login with USER and PASS." << std::endl;
        return;
    }

    passive_mode_ = true;

    // 创建被动套接字
    int passive_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (passive_socket < 0)
    {
        std::cout << "425 Can't open passive connection." << std::endl;
        return;
    }

    // 绑定到任意地址和随机端口
    struct sockaddr_in server_addr;
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = INADDR_ANY;
    server_addr.sin_port = 0; // 让系统选择端口

    if (bind(passive_socket, (struct sockaddr *)&server_addr, sizeof(server_addr)) < 0)
    {
        close(passive_socket);
        std::cout << "425 Can't bind passive connection." << std::endl;
        return;
    }

    // 获取分配的端口
    socklen_t len = sizeof(server_addr);
    if (getsockname(passive_socket, (struct sockaddr *)&server_addr, &len) < 0)
    {
        close(passive_socket);
        std::cout << "425 Can't get passive port." << std::endl;
        return;
    }

    int passive_port = ntohs(server_addr.sin_port);
    data_port_ = passive_port;

    // 开始监听
    if (listen(passive_socket, 1) < 0)
    {
        close(passive_socket);
        std::cout << "425 Can't listen on passive connection." << std::endl;
        return;
    }

    // 设置数据套接字为被动套接字
    data_socket_ = passive_socket;

    // 获取服务器IP
    char ip_str[INET_ADDRSTRLEN];
    data_ip_ = "127.0.0.1"; // 默认本地IP
    // 实际应用中应该获取真实的服务器IP

    // 返回被动模式地址
    std::string pasv_response = "227 Entering Passive Mode (" + data_ip_ + "," +
                                std::to_string(data_port_ / 256) + "," +
                                std::to_string(data_port_ % 256) + ").";
    std::cout << pasv_response << std::endl;
}

// 处理PORT命令（主动模式）
void CommandHandler::HandlePORT()
{
    if (!authenticated_)
    {
        std::cout << "530 Please login with USER and PASS." << std::endl;
        return;
    }

    std::istringstream iss(session_->GetLastCommand());
    std::string cmd, port_info;
    iss >> cmd >> port_info;

    if (port_info.empty())
    {
        std::cout << "501 Syntax error in parameters or arguments." << std::endl;
        return;
    }

    // 解析PORT参数格式: h1,h2,h3,h4,p1,p2
    std::replace(port_info.begin(), port_info.end(), ',', ' ');
    std::istringstream port_iss(port_info);
    int h1, h2, h3, h4, p1, p2;

    if (!(port_iss >> h1 >> h2 >> h3 >> h4 >> p1 >> p2))
    {
        std::cout << "501 Syntax error in parameters or arguments." << std::endl;
        return;
    }

    // 计算IP地址和端口
    std::string client_ip = std::to_string(h1) + "." + std::to_string(h2) + "." +
                            std::to_string(h3) + "." + std::to_string(h4);
    int client_port = (p1 << 8) | p2;

    // 创建主动连接
    int active_socket = socket(AF_INET, SOCK_STREAM, 0);
    if (active_socket < 0)
    {
        std::cout << "425 Can't open active connection." << std::endl;
        return;
    }

    struct sockaddr_in client_addr;
    client_addr.sin_family = AF_INET;
    client_addr.sin_addr.s_addr = inet_addr(client_ip.c_str());
    client_addr.sin_port = htons(client_port);

    if (connect(active_socket, (struct sockaddr *)&client_addr, sizeof(client_addr)) < 0)
    {
        close(active_socket);
        std::cout << "425 Can't connect to client." << std::endl;
        return;
    }

    // 设置数据套接字为主动套接字
    data_socket_ = active_socket;
    data_ip_ = client_ip;
    data_port_ = client_port;

    passive_mode_ = false;
    std::cout << "200 PORT command successful." << std::endl;
}

// 处理TYPE命令（设置传输模式）
void CommandHandler::HandleTYPE()
{
    if (!authenticated_)
    {
        std::cout << "530 Please login with USER and PASS." << std::endl;
        return;
    }

    std::istringstream iss(session_->GetLastCommand());
    std::string cmd, type;
    iss >> cmd >> type;

    if (type.empty())
    {
        std::cout << "501 Syntax error in parameters or arguments." << std::endl;
        return;
    }

    // 转换为大写
    std::transform(type.begin(), type.end(), type.begin(), ::toupper);

    if (type == "A")
    {
        binary_mode_ = false;
        std::cout << "200 Switching to ASCII mode." << std::endl;
    }
    else if (type == "I")
    {
        binary_mode_ = true;
        std::cout << "200 Switching to Binary mode." << std::endl;
    }
    else
    {
        std::cout << "504 Unsupported type." << std::endl;
    }
}

// 处理HELP命令（显示帮助）
void CommandHandler::HandleHELP()
{
    std::cout << "214-The following commands are recognized." << std::endl;
    std::cout << "USER    PASS    CWD     CDUP    MKD     RMD" << std::endl;
    std::cout << "LIST    NLST    RETR    STOR    STOU    DELE" << std::endl;
    std::cout << "PASV    PORT    TYPE    HELP    NOOP    QUIT" << std::endl;
    std::cout << "214 Help command successful." << std::endl;
}

// 处理NOOP命令（无操作）
void CommandHandler::HandleNOOP()
{
    std::cout << "200 NOOP command successful." << std::endl;
}

// 处理QUIT命令（退出）
void CommandHandler::HandleQUIT()
{
    std::cout << "221 Goodbye." << std::endl;
    if (session_)
    {
        session_->Close();
    }
}

// 处理ABOR命令（中断传输）
void CommandHandler::HandleABOR()
{
    if (data_socket_ != -1)
    {
        close(data_socket_);
        data_socket_ = -1;
        std::cout << "226 ABOR command successful." << std::endl;
    }
    else
    {
        std::cout << "226 No transfer in progress." << std::endl;
    }
}

// 获取当前路径
std::string CommandHandler::GetCurrentPath()
{
    return current_path_;
}

// 获取被动模式地址
std::string CommandHandler::GetPassiveAddress()
{
    return data_ip_ + "," + std::to_string(data_port_ / 256) + "," + std::to_string(data_port_ % 256);
}

// 发送数据
void CommandHandler::SendData(const std::string &data)
{
    if (data_socket_ == -1)
    {
        return;
    }

    if (send(data_socket_, data.c_str(), data.size(), 0) < 0)
    {
        logger_->error("Failed to send data: {}", strerror(errno));
    }

    // 关闭数据连接
    close(data_socket_);
    data_socket_ = -1;
}

// 发送文件
bool CommandHandler::SendFile(const std::string &filename)
{
    if (data_socket_ == -1)
    {
        return false;
    }

    std::ifstream file(filename, std::ios::binary);
    if (!file)
    {
        return false;
    }

    char buffer[4096];
    while (!file.eof())
    {
        file.read(buffer, sizeof(buffer));
        int bytes_read = file.gcount();

        if (bytes_read > 0)
        {
            int bytes_sent = send(data_socket_, buffer, bytes_read, 0);
            if (bytes_sent < 0)
            {
                file.close();
                return false;
            }
        }
    }

    file.close();
    close(data_socket_);
    data_socket_ = -1;
    return true;
}

// 接收文件
bool CommandHandler::ReceiveFile(const std::string &filename)
{
    if (data_socket_ == -1)
    {
        return false;
    }

    std::ofstream file(filename, std::ios::binary);
    if (!file)
    {
        return false;
    }

    char buffer[4096];
    int bytes_received;

    while ((bytes_received = recv(data_socket_, buffer, sizeof(buffer), 0)) > 0)
    {
        file.write(buffer, bytes_received);
    }

    file.close();
    close(data_socket_);
    data_socket_ = -1;
    return true;
}
